home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Various
/
DevDisk 65 (1989)(DevWare PD).zip
/
DevDisk 65 (1989)(DevWare PD).adf
/
prosuite
/
xtext.doc
< prev
next >
Wrap
Text File
|
1990-07-11
|
27KB
|
662 lines
XText Programmer's Guide
From the Amiga Programmer's Suite Book 1, by RJ Mical
Copyright (C) 1986, 1987, Robert J. Mical
The document is a programmer's guide to the XText routines.
The main sections of this document are:
o XTEXT INTRODUCTION
o XTEXT PROGRAMMER'S REFERENCE
o XTEXT TECHNICAL REFERENCE
o XTEXT FUNCTION CALLS
=============================================================================
=== XTEXT INTRODUCTION ======================================================
=============================================================================
The XText routines have one purpose: extra-fast text. XText is
intended for Amiga programmers who want high-performance text and
are willing to pay for it. The cost: extra memory usage and fewer
text features. What you get for your investment: brute force
text rendering so fast it singes your eyelashes.
The XText routines attempt to answer a need not satisfied by the
Amiga graphics library's Text() routine. The Text() routine is a
very good, economical, general purpose text generator. It handles
many special text features and uses the graphics library functions
and structures in the correct system way. It obeys all the Amiga
rules of system decency and strives to keep its memory requirements
to an absolute minimum. You can use the Text() routine to create
text that ranges from the plain to the fantastically fancy.
What you can't do with the Text() routine is create very simple text
that avoids the graphics library overhead and that skips its own
overhead by abandoning fancy features and economy in favor of speed.
The XText routines try to avoid as much system overhead as possible.
Wherever appropriate, XText uses memory to gain efficiency. It
foregoes features such as proportional-width fonts and kerning in
favor of rendering speed. It also short-circuits the graphics
library by going directly to the blitter to create the text (though
it does so in a system-honest fashion).
The XText routines have some limitations and drawbacks. The only
fonts that XText handles are fixed-width at 8 bits wide, with no
overlap between characters. If you want fancy algorithmic styles
like underlining, bold, and italics you have to pay for them by
expending RAM, and the cost is significant: typically 2K or 4K of
RAM for each style of text. Also, algorithmic styles take about
one second each for initial setup. Italics don't look as good as
they do when created by the Text() routine, because the italicized
character must still fit in an 8-wide character cel (although you
can get around this problem by creating your own italics font).
But though the cost of XText is significant, the benefit is
significant too: regardless of the font, regardless of the
algorithmic style, XText() outputs characters to a Workbench
window at approximately 18,500 characters per second in the
fast fat mode, and 14,500 per second in slow slim mode.
By comparison, the Text() routine outputs characters at
approximately 3,800 per second, depending on what algorithmic
style you've selected (4,000 if plain text is selected).
For those who have the memory to spare, XText provides a
high-performance alternative to normal Amiga text rendering.
=============================================================================
=== XTEXT PROGRAMMER'S REFERENCE ============================================
=============================================================================
This section describes how programmers use the XText routines.
An important note: if you are using the Metacomco assembler when
compiling .asm files, you must comment out the definition of the
constant AZTEC in the xtext.i file. If you are using the Aztec
assembler, you must define the constant named AZTEC in the xtext.i
file. This is because the Aztec assembler uses some non-standard
syntax, so special steps must be taken to define things correctly.
=== Plain XText Usage =======================================================
Using basic XText is actually quite simple.
The XText() routine requires an initialized XTextSupport structure
to do its work. You get an XTextSupport structure by calling the
MakeXTextSupport() routine. This routine allocates an XTextSupport
structure for you and initializes it such that if all you want to
do is create plain text, you can use the support structure as is.
The MakeXTextSupport() routine accepts an argument of note: the
address of a TextAttr structure. You use this argument to specify
the font to be used with your calls to XText(). With this argument
you can specify that the XText() routine will use a disk-based font
rather than the system's topaz.font. You can use any 8-bit wide
font, even a font of your own design!
Once you've gotten an XTextSupport structure from MakeXTextSupport(),
you create text by calling the XText() routine. The arguments to
the XText() routine are simple; refer to the XText() autodoc header
for details.
If you like, you can set FrontPen, BackPen and DrawMode in your
XTextSupport structure before you call XText(). The characters
normally are rendered in the FrontPen color. The space around
the characters is rendered in the BackPen color. The FrontPen is
initialized to 1 and the BackPen to 0, but you can change them to
anything you prefer. The DrawMode works according to the DrawMode
rules as illuminated in the Text chapter of the ROM Kernel Manual.
Briefly:
Draw Mode Result
---------------------- ---------------------------------------------------
JAM2 Normal text, overwrites everything
JAM1 Overstrike text, writes only the character imagery
COMPLEMENT Where there's character imagery, xor's background
JAM2 + INVERSVID Normal text, pens reversed
JAM1 + INVERSVID Writes blanks around character imagery in FrontPen
COMPLEMENT + INVERSVID Kind of a weird reverse exclusive-or
Text clipping works like it does with the Text() routine, which is
to say that text clips fine with Intuition windows and doesn't clip
at all with graphics rastports that you create yourself.
When you're done calling XText() (usually when your program is
terminating), you call UnmakeXTextSupport() to deallocate your
XTextSupport structure and all of the resources associated with it.
And that's it! Easy, eh?
=== Advanced XText Techniques ===============================================
When you call MakeXTextSupport() you get to preset the Flags variable
of your new XTextSupport structure before anything else is done with the
structure. Mostly notably, you can preset the SLIM_XTEXT flag.
The SLIM_XTEXT flag allows you to specify that you want the slower, slimmer
XText technique, which uses half as much memory as the faster, fatter
XText technique but runs about 20% slower.
If you want to have algorithmic styles for your text, you must create
them with calls to the MakeXTextFont() routine after you've gotten
an XTextSupport structure.
To do this, you start with an initialized TextAttr structure.
Set the TextAttr's ta_Style field to the font attributes you want;
your choices are combinations of FSF_BOLD, FSF_UNDERLINED and FSF_ITALIC.
Then call MakeXTextFont() with the address of this TextAttr and the
address of your XTextSupport structure, along with a font select
index. The font select index will be used to save the new font data
pointer in the XTextSupport's FontData[] array.
Later, before calling XText(), you can set the XTextSupport variable
FontSelect to describe which of the fonts you want used for the
subsequent XText() calls.
You find the FontSelect definitions in xtext.h. They have names
like NORMAL_FONT, ULINE_FONT, and ITALIC_BOLD_FONT. Of course
there's also the ever-popular ITALIC_ULINE_BOLD_FONT if you need
it, though this font tends to look as muddy as the name.
Actually, the FontSelect definitions are just names for the indices
into the FontData[] array. You can make up your own names if you
like. Also, when calling MakeXTextFont(), you can have the TextAttr
refer to different fonts or any combination of fonts and styles.
It's up to you! All XText expects is that FontSelect has a valid
index into FontData[].
By the way, the MakeXTextSupport() routine initializes the entire
FontData[] array with the address of the NORMAL_FONT structure, so
if you make a mistake and select a font that you hadn't initialized
you'll get plain text.
If you want, there's no restriction against creating multiple
XTextSupport structures to support multiple fonts.
Italics are a problem. The italics of a normal font are skewed
such that they cover more than 8 bits of character imagery. As only
8 bits of the final imagery can be used, a decision has to be made
regarding which of the 8 bits will be used. The default is defined
by the constant ITALIC_LEFT_EDGE, which describes the first column of
bits on the left that will be used for the final imagery. If you
don't like how your italics look, you can try playing with the value
of this constant.
Part of the XText speed is achieved by having a pre-initialized BitMap
in the XTextSupport structure. If you're ever going to change the
OutputRPort pointer in your support structure, you must re-initialize
the TextBitMap.
One last note: in the XTextSupport structure is a Remember key, which
is used to track all of the memory allocations required to support
your XText usage. You can use this key to make further allocations
as needed. FreeRemember() is called with this key when you call
UnmakeXTextSupport().
=============================================================================
=== XTEXT TECHNICAL REFERENCE ===============================================
=============================================================================
This section presents a tutorial of how the XText() routine works.
It is meant to augment a reading of the xtext.asm file. Maybe you can
learn something about pushing that old Amiga around!
=== XText Theory of Operation ===============================================
The XText theory is relatively simple. It's all brute force and shortcuts.
The characters are restricted to a width of exactly 8 bits. This allows
character imagery to be handled as byte-sized quantities, which is a
very handy quantity for the Amiga to use. You might think that the
68000 is employed to move the data around, but a further minor
requirement -- namely that all buffers must be an even number of
bytes wide -- allows the brute force of the blitter to assist in
blasting the text into the display.
To create a line of text, XText uses shortcut techniques to quickly
construct a bitmap that represents the text.
XText starts by building a single plane of normal character imagery
(character data bits set, background bits clear) in an imagery plane
called the NormalTextPlane. This plane is built one of two ways:
the normal technique uses a word of data for each byte of character
imagery in order to utilize the blitter when building the
NormalTextPlane; the "slim" technique which uses the only a byte of
data for each byte of character imagery and uses the processor to
build the NormalTextPlane. The actual mechanics of this is described
in detail below.
As needed, the NormalTextPlane is inverted (character bits clear,
background bits set) into the InvertedTextPlane. These two planes
of text are then used with two other pre-initialized planes, the
AllClearPlane plane of all bits clear and AllSetPlane plane of
all bits set, to create the text display.
Using these four planes, one can construct a bitmap of all possible pen
settings for the foreground and background of the character imagery.
Consider this table of all possible combinations of corresponding bits
of the character and background colors:
Foreground Background
Bit Bit
----- -----
0 0 Use AllClearPlane
0 1 Use InvertedTextPlane
1 0 Use NormalTextPlane
1 1 Use AllSetPlane
XText() plugs the plane pointers according to the above table into a
pre-initialized BitMap structure, and finally calls the graphics
library's BltBitMapRastPort() function to move the text into the
destination raster. BltBitMapRastPort() works both with Intuition
windows and with rastports that have no associated layer
("roll your own" rasters).
Actually, when the drawing mode is JAM1 the text must be "cookie cut"
into the background by using the NormalTextPlane as a mask for a call
to (grit your teeth here) BltMaskBitMapRastPort(). Because an extra
blitter source and extra handling is required by this routine,
performance is noticeably degraded. Avoid JAM1 where possible.
In any event, with so many of the pieces pre-initialized and with the
blitter whipped into a font frenzy, perhaps you can understand why
these routines work reasonably fast.
Note that if the foreground and background pens are equal, the normal
and inverted planes don't need to be constructed as they'll never be
used. An optimization that evolves out of this fact is that you can
fill a line or part of a line of your text with spaces (blank
characters) much more quickly by setting the foreground pen equal to
the background pen. The trick with this optimization is to not spend
too much time detecting whether or not an area of text is all blank,
for you may lose the increased performance during the handling of
normal text lines.
Actually, if the foreground and background pens are equal and therefore
a blank line will be output, it would be much more efficient to skip
all of this work and call the graphics library's RectFill() routine.
This is left as an exercise for the reader.
A further optimization: I'm guessing that many text calls will not
require the inverted plane, so it won't be made until it's needed.
If programmers follow the Intuition-encouraged standard of pen 1 for
foreground and pen 0 for background, then the bits are:
Foreground pen (in binary) -- 00001
Background pen (in binary) -- 00000
Foreground Background
Bit Bit
----- -----
0 0 Use AllClearPlane for plane 4
0 0 Use AllClearPlane for plane 3
0 0 Use AllClearPlane for plane 2
0 0 Use AllClearPlane for plane 1
1 0 Use NormalTextPlane for plane 0
No need to invert here! So the inverted plane would never be made.
In fact, if the text is *any* color against a background of zero,
this optimization works. The cost of this technique is that I have
to check a flag once per time that I find an inverted bit plane is
called for (6 times maximum (though of course Dale would say 8
times maximum)), and the savings is in avoiding an unnecessary
inversion (big savings).
Because the blitter is word-size oriented, in order to use the blitter
most efficiently this routine always works with character pairs while
building the buffers. This allows the blitter to always pick up two
characters, use a byte from each, and write a single word. No extra
checking needs to be done, no special handling of the odd character.
If you specify an odd number of characters, this routine will round
up the character count to the next higher even number and then build
the buffer with that many characters. However, only the number of
characters you specify will actually be printed to the screen. The
overhead cost to process the extra character is nominal, while the
performance improvement gained by using the blitter and skipping the
overhead is great.
The XText font imagery is laid out in one of two ways, depending on
whether you want fast fat XText or slow slim XText. The fast fat
technique runs about 20% faster than the slow and slim. Also,
fast fat XText uses twice as much memory as the slow slim way,
typically 4K of CHIP RAM for each algorithmic style as compared
with 2K. You might be willing to expend the extra memory if you
want the extra performance. You specify that you want the slimmer
XText by passing SLIM_XTEXT as one of the flags that you supply to
the MakeXTextSupport() routine.
The fast fat XText technique is penny foolish but pound wise
(to mangle a cliche). Again, one of the keys to this design is to
improve performance by leveraging off of the blitter's capabilities.
Each byte of character imagery is laid out in a word of memory where
the first byte contains the imagery and the second byte is blank.
Why spread the imagery out like this? This allows the blitter to
always process two characters at a time, with the first character
loaded into the blitter's high byte and the second character
shifted right 8 bits into the low byte using the blitter's
delightfully fast barrel shifter. The two characters are then laid
down in one stroke, thereby further minimizing computational overhead.
The drawback of this fast fat technique is that it requires twice as
much memory as a normal font. The formula for font requirement is:
256 * character height * 2. For example, to create an XText version
of topaz.font requires 256 characters * 8 rows * 2 bytes per row = 4096
bytes. Do you think it's worth it?
The slim technique uses the processor to build the text plane, so
there is no blitter requirement of using one word for each byte of
image data. It's byte for byte, which cuts memory usage in half.
But using the processor takes much longer than using the blitter
to build the text plane, typically a total of 20% longer.
=============================================================================
=== XTEXT FUNCTION CALLS ====================================================
=============================================================================
CONTENTS:
MakeXTextFont()
MakeXTextSupport()
UnmakeXTextSupport()
XText()
*** MakeXTextFont() ******************************************************
NAME
MakeXTextFont -- Make font imagery for the XText routines
SYNOPSIS
UBYTE *MakeXTextFont(TextAttr, XTextSupport, Index);
FUNCTION
This routine creates font imagery in the format that the XText()
routine uses. It allocates the font data buffer and then constructs
the XText font imagery in this buffer using the imagery of the
font specified by the TextAttr argument.
This routine is normally called by MakeXTextSupport(). You do not
need to use this routine unless you want to create fonts that
have special styles such as bold, underline, and italics.
If all is successful, this routine writes the address of the font
data buffer in the XTextSupport's FontData array at the Index position,
and returns the address of the new font data buffer.
If anything goes wrong, the FontData array is unchanged and this
routine returns NULL.
You can specify font styles in your TextAttr structure.
If the TextAttr argument is equal to NULL, the system's 80-column
"topaz.font" will be used instead.
You must have called MakeXTextSupport() before calling this routine,
as this routine requires an initialized XTextSupport structure.
All memory allocations are attached to the XTextSupport structure's
Remember key.
INPUTS
TextAttr = a pointer to a TextAttr structure specifying the font
to be used for this XText font imagery. If the TextAttr
argument is equal to NULL, the system's 80-column "topaz.font"
will be used.
XTextSupport = a pointer to an initialized XTextSupport structure,
which structure is created by a call to MakeXTextSupport().
Index = index into the XTextSupport's FontData array for this font
RESULT
Returns a pointer to the memory block that contains the font imagery.
If anything goes wrong (usually out of memory), returns NULL.
EXAMPLE
struct XTextSupport *xtext;
struct TextAttr localTextAttr = { ... };
xtext = MakeXTextSupport(...);
[Make a BOLD font for XText() calls]
localTextAttr.ta_Style = FSF_BOLD;
MakeXTextFont(&localTextAttr, xtext, BOLD_FONT);
[Write some BOLD characters]
xtext->FontSelect = BOLD_FONT;
XText(...);
BUGS
Well, if there is a bug it's a highly technical one that most
of you can ignore. I'm not sure that it's entirely 100% for sure
safe to work with DiskfontBase the way I have below and still expect
this program to be re-entrant. It should be OK up to and including
the 1.2 release of the system, but in the future this could cause
some very mysterioso bug.
SEE ALSO
MakeXTextSupport(), XText(), UnmakeXTextSupport()
*** MakeXTextSupport() ***************************************************
NAME
MakeXTextSupport -- Allocate and initialize XText Support data
SYNOPSIS
struct XTextSupport *MakeXTextSupport(RastPort, TextAttr,
MaxTextWidth, InitialFlags);
FUNCTION
This routine allocates an XTextSupport structure and initializes
the structure for use by the XText routines.
The font specified by the TextAttr argument is opened. If the
TextAttr arg is equal to NULL, the system font "topaz.font" is
opened instead. If you are specifying a TextAttr, the font you
specify must have a character cel that is 8-bits wide.
Image data from this font is then used to create the special
font data used by the XText routines. The address of this data
is put in the FontData variable of the XTextSupport structure,
as well as in all of the elements in the SpecialFontData array.
The MaxTextWidth argument describes the maximum number of
characters that you will ever print at one time with the
XText() routine. Typically this number will be 80 or 40,
depending on whether your display is high-res or low-res.
This number should be an even number; if the number you
supply is odd, the actual number used will be your number
rounded up to the next even number.
The InitialFlags argument is used to preset your XTextSupport's
Flags variable before anything is done with the structure.
See the file xtext.h for the definitions of the XTextSupport
structure's Flags.
An InitialFlag of note is the SLIM_XTEXT flag, which you can
set to define that you want the slim (and slow) XText technique
to be used when the XText font data is created and when
XText is rendered to the display. The advantage of SLIM_XTEXT
is that the technique requires half as much memory as the
fast fat technique. The disadvantage is that it runs about
20% more slowly than fast fat XText.
After you have called MakeXTextSupport(), you can use
the Remember key in the XTextSupport structure -- named
XTextKey -- for further memory allocations. All memory
allocations made using XTextKey are freed when
UnmakeXTextSupport() is called.
INPUTS
RastPort = a pointer to the RastPort that will be the destination
for text created by the XText routines. Typically, this
will be the RastPort of an Intuition window or screen
that you've opened. For an example, see EXAMPLE below.
TextAttr = a pointer to a TextAttr structure specifying the font
to be used for this XText font imagery. If the TextAttr
argument is equal to NULL, the system's 80-column "topaz.font"
will be used.
MaxTextWidth = Maximum number of characters per line. This should
be an even number, and if odd will be rounded up to the
next even number.
InitialFlags = Flags that will be preset in your XTextSupport's
Flags variable before anything is done with the structure.
See the file xtext.h for the definitions of the XTextSupport
structure's Flags.
RESULT
Returns the address of the XTextSupport structure, or NULL
if there were any problems (usually out of memory).
EXAMPLE
window = OpenWindow( ... );
xtext = MakeXTextSupport(window->RPort, &DiskFontTextAttr, 80, NULL);
- or, as another example, open a 320 screen and ... -
screen = OpenScreen( ... );
xtext = MakeXTextSupport(&screen->RastPort, NULL, 40, SLIM_XTEXT);
SEE ALSO
MakeXTextFont(), XText(), UnmakeXTextSupport()
*** UnmakeXTextSupport() *************************************************
NAME
UnmakeXTextSupport -- Free the XTextSupport structure and buffers
SYNOPSIS
UnmakeXTextSupport(XTextSupport)
FUNCTION
Frees the XTextSupport structure and buffers.
INPUTS
XTextSupport = pointer to an XTextSupport structure (typically
created by a call to MakeXTextSupport() )
RESULT
None
SEE ALSO
MakeXTextSupport()
*** XText() **************************************************************
NAME
XText -- Write a line of text using the XText technique
SYNOPSIS
XText(XTextSupport, Text, CharCount, XPos, YPos);
FUNCTION
Writes a line of text using the parameters in the XTextSupport
structure.
The Text argument points to a line of text. This text doesn't have
to be null-terminated. CharCount describes how many characters
of Text should be printed.
The XPos and YPos values describe the top-left corner for the
text. Note that this is different from the x and y coordinate
system used by the graphics library's Text() routine, where the
coordinates refer to the baseline of the text.
Before calling this routine you can set the FrontPen, BackPen,
DrawMode and FontSelect in your XTextSupport structure.
Also, there are several other initializations that you may wish
to perform with your support structure. Refer to the
XText Programmer's Guide for more information.
INPUTS
XTextSupport = Pointer to an XTextSupport structure (typically
created by a call to MakeXTextSupport() )
Text = Pointer to the text that you want output. This text
doesn't have to be null-terminated
CharCount = The number of characters to be printed
XPos, YPos = The position for the top-left corner of the output
RESULT
None
EXAMPLE
struct XTextSupport *xtext;
xtext = MakeXTextSupport(...);
xtext->FrontPen = 3;
xtext->BackPen = 2;
XText(xtext, "Hello World!", 12, 25, 87);
SEE ALSO
MakeXTextSupport(), MakeXTextFont()